// Learn cc.Class:
//  - https://docs.cocos.com/creator/manual/en/scripting/class.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

cc.Class({
    extends: cc.Component,
    ctor(){
        this._w = 0;
        this._h = 0;
        this.stepW = 0;
        this.stepH = 0;
        this.level = 4;
        this.lineColor = '#f00';
        this.fontColor = '#f00'
        this.lineW = 3;
        this.max = 0;
        this.updateMaxCount = 0;
        this.moveIng = false;
        this.blockData = [];
        this.colors = ['#00BFFF', '#808000', '#F5DEB3', '#00FF00', '#FFC0CB', '#FF00FF', '#87CEEB', '#708090', '#FF8C00']
        this.startBlockData = [
            {
                val: 1,
                x: 0, 
                y: 0
            },
            {
                val: 1,
                x: 1, 
                y: 0
            },    
            {
                val: 2,
                x: 2, 
                y: 0
            },              
            {
                val: 1,
                x: 2, 
                y: 1
            },                                
        ]
    },
    properties: {
        pen: cc.Graphics,
        bg: cc.Node,
        blocks: cc.Node,
        block: cc.Prefab,
        score: cc.Label,
    },
    onLoad () {
        this._w = this.bg.width;
        this._h = this.bg.height;
        this.initGrid();
        this.initBlockData();
        this.addBlockData();
        this.initTouchEvent();
    },
    resetGame(){
        this.blocks.removeAllChildren();
        this.initBlockData();
        this.addBlockData();
        this.max = 0;
        this.updateMaxCount = 0;     
        this.score.string = this.max;   
        this.moveIng = false;
    },
    initGrid(){
        let stepW = this.stepW = this._w / this.level;
        let stepH = this.stepH = this._h / this.level;
        this.pen.strokeColor = this.lineColor;
        this.pen.lineWidth = this.lineW;
        for(let i=1; i<this.level; i++){
            //x
            this.pen.moveTo(stepW*i, 0)
            this.pen.lineTo(stepW*i, this._h)
            //y
            this.pen.moveTo(0, stepH*i)
            this.pen.lineTo(this._w, stepH*i)
        }
        this.pen.stroke();
    },
    initBlockData(){
        let arr = [];
        for(let i=0; i<this.level; i++){
            let arr2 = [];
            for(let j=0; j<this.level; j++){
                arr2.push(0)
            }
            arr.push(arr2)
        }
        this.blockData = arr;
    },
    addBlockData(){
        for(let i=0; i<this.startBlockData.length; i++){
            let cur = this.startBlockData[i]
            let x = cur.x;
            let y = cur.y;
            let val = cur.val;
            this.blockData[x][y] = val;
            this.createBlock(cur)
            if(this.blockData[x][y] > this.max){
                this.max = this.blockData[x][y];
            }
        }
        console.table(this.blockData)
    },
    createBlock({x, y, val}){
        let block = cc.instantiate(this.block);
        block.color = this.getRndColor();
        block.width = this.stepW;
        block.height = this.stepH;        
        block.setPosition(cc.v2(x*this.stepW, y*this.stepH))
        let blockChildNode = block.getChildByName('val');
        blockChildNode.setPosition(cc.v2(this.stepW/2, this.stepH/2))
        let label = blockChildNode.getComponent(cc.Label);
        label.string = val;
        block.curPos = {x, y};
        block.toPos = {x, y};
        block.willDestory = false;
        block.isPlus = false;
        this.blocks.addChild(block)
    },
    initTouchEvent(){
        let startPos = null;
        this.node.on('touchstart', (e)=>{
            if(this.moveIng){
                return false;
            }
            startPos = e.getLocation();
        })
        this.node.on('touchend', (e)=>{
            if(this.moveIng){
                return false;
            }            
            let endPos = e.getLocation();
            let dis = endPos.sub(startPos);
            let dir = null;
            if(dis.x < 0 && Math.abs(dis.x) > Math.abs(dis.y)){
                dir = cc.v2(-1, 0)
            }
            if(dis.x > 0 && Math.abs(dis.x) > Math.abs(dis.y)){
                dir = cc.v2(1, 0)
            }   
            if(dis.y < 0 && Math.abs(dis.x) < Math.abs(dis.y)){
                dir = cc.v2(0, -1)
            }    
            if(dis.y > 0 && Math.abs(dis.x) < Math.abs(dis.y)){
                dir = cc.v2(0, 1)
            }
            if(dir){
                this.blockMove(dir);
            }
        })
    },
    updateMax(n){
        this.max = n;
        this.updateMaxCount++;
        this.score.string = this.max;
        if(this.max == 2048){
            console.log('游戏结束')
            this.resetGame();
        }
    },
    blockMove(dir){
        for(let i=0; i<this.level; i++){
            for(let j=0; j<this.level; j++){
                //向左移动
                if(dir.x == -1 && dir.y == 0){
                    let cur = this.blockData[j][i];
                    if(cur != 0){
                        let curNode = this.getNodeByKey(j, i);
                        let tarX = j;
                        let hasNode = false;
                        while(!hasNode && tarX > 0){
                            tarX--;
                            if(this.blockData[tarX][i] != 0){
                                hasNode = true;
                            }
                            //有方块
                            if(hasNode){
                                let prevBlock = this.getNodeByKey(tarX, i, true)
                                //前面有方块，并且没有吃过其它方块
                                if(this.blockData[tarX][i] == cur && !prevBlock.willDestory && !prevBlock.isPlus && !curNode.isPlus){
                                    cur+=this.blockData[tarX][i];
                                    this.blockData[tarX][i] = 0;
                                    prevBlock.willDestory = true;
                                    hasNode = false;
                                    
                                    curNode.isPlus = true;
                                    if(cur > this.max){
                                        this.updateMax(cur)
                                    }
                                }
                            }

                        }
                        if(tarX == j || hasNode && tarX+1 == j){
                            curNode.toPos = curNode.curPos;
                        }else if(hasNode && tarX+1 != j){
                            curNode.toPos = {x: tarX+1, y: i}
                            this.blockData[tarX+1][i] = cur;
                            this.blockData[j][i] = 0;
                        }else{
                            curNode.toPos = {x: tarX, y: i}
                            this.blockData[tarX][i] = cur;
                            this.blockData[j][i] = 0;
                        }
                    }
                //向右移动
                }else if(dir.x == 1 && dir.y == 0){
                    let cur = this.blockData[this.level-j-1][i];
                    if(cur != 0){
                        let curNode = this.getNodeByKey(this.level-j-1, i);
                        let tarX = this.level-j-1;
                        let hasNode = false;
                        while(!hasNode && tarX < this.level-1){
                            tarX++;
                            if(this.blockData[tarX][i] != 0){
                                hasNode = true;
                            }
                            if(hasNode){
                                let prevBlock = this.getNodeByKey(tarX, i, true);
                                //有方块，并且数值相同
                                if(this.blockData[tarX][i] == cur && !prevBlock.willDestory && !prevBlock.isPlus  && !curNode.isPlus){
                                    cur+=this.blockData[tarX][i];
                                    this.blockData[tarX][i] = 0;
                                    prevBlock.willDestory = true;
                                    curNode.isPlus = true;
                                    hasNode = false;
                                    if(cur > this.max){
                                        this.updateMax(cur)
                                    }
                                }                                     
                            }
                        }
                        if(tarX == this.level-j-1 || hasNode && tarX-1 == this.level-j-1){
                            curNode.toPos = curNode.curPos;
                        }else if(hasNode && tarX-1 != this.level-j-1){
                            curNode.toPos = {x: tarX-1, y: i}
                            this.blockData[tarX-1][i] = cur;
                            this.blockData[this.level-j-1][i] = 0;
                        }else{
                            curNode.toPos = {x: tarX, y: i}
                            this.blockData[tarX][i] = cur;
                            this.blockData[this.level-j-1][i] = 0;
                        }
                    }
                //向下移动
                }else if(dir.x == 0 && dir.y == -1){
                    let cur = this.blockData[i][j];
                    if(cur != 0){
                        let curNode = this.getNodeByKey(i, j);
                        let tarY = j;
                        let hasNode = false;
                        while(!hasNode && tarY > 0){
                            tarY--;
                            if(this.blockData[i][tarY] != 0){
                                hasNode = true;
                            }
                            if(hasNode){
                                //有方块，并且数值相同
                                let prevBlock = this.getNodeByKey(i, tarY, true);
                                if(this.blockData[i][tarY] == cur && !prevBlock.willDestory && !prevBlock.isPlus  && !curNode.isPlus){
                                    cur+=this.blockData[i][tarY];
                                    this.blockData[i][tarY] = 0;
                                    this.getNodeByKey(i, tarY, true).willDestory = true;
                                    hasNode = false;
                                    curNode.isPlus = true;
                                    if(cur > this.max){
                                        this.updateMax(cur)
                                    }                                
                                } 
                            }
                        }
                        if(tarY == j || hasNode && tarY+1 == j){
                            curNode.toPos = curNode.curPos;
                        }else if(hasNode && tarY+1 != j){
                            curNode.toPos = {x: i, y: tarY+1}
                            this.blockData[i][tarY+1] = cur;
                            this.blockData[i][j] = 0;
                        }else{
                            curNode.toPos = {x: i, y: tarY}
                            this.blockData[i][tarY] = cur;
                            this.blockData[i][j] = 0;
                        }
                    }            
                //向上移动        
                }else if(dir.x == 0 && dir.y == 1){
                    let cur = this.blockData[j][this.level-i-1];
                    if(cur != 0){
                        let curNode = this.getNodeByKey(j, this.level-i-1);
                        let tarY = this.level-i-1;
                        let hasNode = false;
                        while(!hasNode && tarY < this.level-1){
                            tarY++;
                            if(this.blockData[j][tarY] != 0){
                                hasNode = true;
                            }
                            if(hasNode){
                                let prevBlock = this.getNodeByKey(j, tarY, true);
                                //有方块，并且数值相同
                                if(this.blockData[j][tarY] == cur && !prevBlock.willDestory && !prevBlock.isPlus  && !curNode.isPlus){
                                    cur+=this.blockData[j][tarY];
                                    this.blockData[j][tarY] = 0;
                                    this.getNodeByKey(j, tarY, true).willDestory = true;
                                    hasNode = false;
                                    curNode.isPlus = true
                                    if(cur > this.max){
                                        this.updateMax(cur)
                                    }                                
                                }   
                            }
                           
                        }
                        if(tarY == this.level-i-1 || hasNode && tarY-1 == this.level-i-1){
                            curNode.toPos = curNode.curPos;
                        }else if(hasNode && tarY-1 != this.level-i-1){
                            curNode.toPos = {x: j, y: tarY-1}
                            this.blockData[j][tarY-1] = cur;
                            this.blockData[j][this.level-i-1] = 0;
                        }else{
                            curNode.toPos = {x: j, y: tarY}
                            this.blockData[j][tarY] = cur;
                            this.blockData[j][this.level-i-1] = 0;
                        }
                    }  
                }
            }
        }
        //每次移动添加一个方块
        setTimeout(()=>{
            this.addOneBlock()
        },500)
        this.moveIng = true;
        //开始移动方块
        this.startMove();
        
    },
    addOneBlock(){
        //console.log(this.updateMaxCount, this.updateMaxCount/2)
        let num = (Math.random()*(this.updateMaxCount - this.updateMaxCount/2) + this.updateMaxCount/4|0 ) | 0;
        
        let rndNum = Math.pow(2, num);
        console.log(rndNum, this.max)
        let pos = this.getRndPos();
        if(pos){
            let obj = {
                x: pos.x,
                y: pos.y,
                val: Number(rndNum)
            }
            
            this.blockData[pos.x][pos.y] = obj.val;
            this.createBlock(obj)
        }else{
            if(this.isGameOver()){
                console.log('游戏结束')
                this.resetGame();
            }
        }
    },
    isGameOver(){
        let blockData = this.blockData;
        let isOver = true;
        for(let i=0; i<this.level-1; i++){
            for(let j=0; j<this.level-1; j++){
                if(blockData[i][j] == blockData[i+1][j] || blockData[i][j] == blockData[i][j+1]){
                    isOver = false;
                }
            }
        }
        return isOver;
    },
    getRndPos(){
        let arr = [];
        for(let i=0; i<this.level; i++){
            for(let j=0; j<this.level; j++){
                if(this.blockData[i][j] == 0){
                    arr.push({x: i, y: j})
                }
            }
        }
        arr.sort(()=>{
            return Math.random() - 0.5
        })
        console.log(arr);
        if(arr.length != 0){
            return arr[0]
        }else{
            return null
        }
    },
    startMove(){
        let child = this.blocks.children;
        for(let i=0; i<child.length; i++){
            let cur = child[i];
            let curPos = cur.curPos;
            let toPos = cur.toPos;
            cc.tween(cur).by(0.5, {
                position: cc.v2( (toPos.x - curPos.x) * this.stepW,  (toPos.y - curPos.y) * this.stepH)
            }).call(()=>{
                cur.curPos = cur.toPos;
                cur.isPlus = false;
                if(cur.willDestory){
                    cur.parent.removeChild(cur)
                }
                this.moveIng = false;
                cur.children[0].getComponent(cc.Label).string = this.blockData[cur.curPos.x][cur.curPos.y];
            }).start();
        }
    },
    getNodeByKey(x, y, isToPos){
        let child = this.blocks.children;
        let item = child.filter(item=>{
            if(isToPos){
                return item.toPos.x == x && item.toPos.y == y
            }else{
                return item.curPos.x == x && item.curPos.y == y
            }
        })
        return item[0];
    },
    getRndColor(){
        let len = this.colors.length;
        let rnd = Math.random()*len|0;
        let color = new cc.Color();
        color.fromHEX(this.colors[rnd])
        return color
    },
    start () {

    },

    // update (dt) {},
});
